package exam_serv

import (
	"context"
	"encoding/json"
	"strconv"
	"strings"
	"ubt-aio-service/app/mod/exam_mod"
	"ubt-aio-service/app/pkg/db"
	"ubt-aio-service/app/pkg/logger"
	"ubt-aio-service/app/utils"
)

type quest struct{}

var QstServ = quest{}

// Add 新增
func (s *quest) Add(req *exam_mod.QstSaveReq) *utils.ResJson {
	// 去掉主键，改为自动赋值模式
	sqlStr := "INSERT INTO exam_base(qst_id, kind, qst_no, title, answer, keywords, file_names, file_urls, remarks, states, add_time, upd_time) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, 1, EXTRACT(epoch FROM NOW()), EXTRACT(epoch FROM NOW()))"
	return db.CudData(sqlStr, req.QstId, req.Kind, req.QstNo, req.Title, req.Answer, req.Keywords, req.FileNames, req.FileUrls, req.Remarks)
}

// Exists 判断是否重复
func (s *quest) Exists(req *exam_mod.QstExtVo) bool {
	// 注意修改对应的变量值
	sqlStr := "SELECT qst_id FROM exam_base WHERE states=1 AND title=$1 AND qst_no=$2 AND kind=$3"
	param := make([]any, 0)
	param = append(param, req.Title)
	param = append(param, req.QstNo)
	param = append(param, req.Kind)
	if req.QstId != "" {
		sqlStr += " AND qst_id!=$4"
		param = append(param, req.QstId)
	}
	if res := db.GetOne(sqlStr, param...); res.Code == utils.Succeed.Code {
		return true
	}
	return false
}

// Update 修改
func (s *quest) Update(req *exam_mod.QstSaveReq) *utils.ResJson {
	// 注意最后的索引值修改，以及去掉不需要修改的值
	sqlStr := "UPDATE exam_base SET kind=$1, qst_no=$2, title=$3, answer=$4, keywords=$5, file_names=$6, file_urls=$7, remarks=$8, upd_time=EXTRACT(epoch FROM NOW()) WHERE qst_id=$9"
	// 需要将第一个值放到最后
	return db.CudData(sqlStr, req.Kind, req.QstNo, req.Title, req.Answer, req.Keywords, req.FileNames, req.FileUrls, req.Remarks, req.QstId)
}

// CacheOpts 缓冲更新答案选项
func (s *quest) CacheOpts(ch chan int) {
	sqlStr := "SELECT a.opt_id, a.qst_id, a.opt_no, a.opt_name, a.img_names, a.img_urls, a.iz_right, a.answer, a.keywords, a.remarks, a.states, a.add_time, a.upd_time FROM exam_option a WHERE a.states=1 ORDER BY a.qst_id, a.opt_no"
	res := db.GetAll(sqlStr)
	if res.Code == utils.Succeed.Code {
		jsonBytes, err := json.Marshal(res.Data)
		if err != nil {
			logger.Error("数据转换失败。" + err.Error())
			return
		}
		ctx := context.Background()
		if err = db.RdsCli.Set(ctx, "opts", string(jsonBytes), 0).Err(); err != nil {
			logger.Error("数据缓冲失败。" + err.Error())
			return
		}
	}
	<-ch
}

// DelOptByQst 删除
func (s *quest) DelOptByQst(ch chan int, qstId string) {
	sqlStr := "DELETE FROM exam_option WHERE qst_id=$1"
	db.CudData(sqlStr, qstId)
	<-ch
}

// AddOpts 新增答案选项
func (s *quest) AddOpts(ch chan int, list []*exam_mod.OptSaveReq) {
	var (
		param []any
		n     = 0
	)
	sqlStr := "INSERT INTO exam_option(opt_id, qst_id, opt_no, opt_name, img_names, img_urls, iz_right, answer, keywords, remarks, states, add_time, upd_time) VALUES "
	for _, req := range list {
		sqlStr += "($" + strconv.Itoa(n+1) + ", $" + strconv.Itoa(n+2) + ", $" + strconv.Itoa(n+3) + ", $" + strconv.Itoa(n+4) + ", $" + strconv.Itoa(n+5) + ", $" + strconv.Itoa(n+6) + ", $" + strconv.Itoa(n+7) + ", $" + strconv.Itoa(n+8) + ", $" + strconv.Itoa(n+9) + ", $" + strconv.Itoa(n+10) + ", 1, EXTRACT(epoch FROM NOW()), EXTRACT(epoch FROM NOW())),"
		param = append(param, req.OptId)
		param = append(param, req.QstId)
		param = append(param, req.OptNo)
		param = append(param, req.OptName)
		param = append(param, req.ImgNames)
		param = append(param, req.ImgUrls)
		param = append(param, req.IzRight)
		param = append(param, req.Answer)
		param = append(param, req.Keywords)
		param = append(param, req.Remarks)
		n += 10
	}
	sqlStr = sqlStr[:len(sqlStr)-1]
	db.CudData(sqlStr, param...)
	<-ch
}

// Deletes 删除
func (s *quest) Deletes(ids string) *utils.ResJson {
	var (
		param []any
		q     string
		n     = 0
	)
	idList := strings.Split(ids, ",")
	for _, curId := range idList {
		n++
		q += "$" + strconv.Itoa(n) + ","
		param = append(param, curId)
	}
	q = q[:len(q)-1]
	sqlStr := "UPDATE exam_base SET states=2, upd_time=EXTRACT(epoch FROM NOW()) WHERE qst_id IN (" + q + ")"
	return db.CudData(sqlStr, param...)
}

// DelOptsByQst 删除
func (s *quest) DelOptsByQst(ch chan int, ids string) {
	var (
		param []any
		q     string
		n     = 0
	)
	idList := strings.Split(ids, ",")
	for _, curId := range idList {
		n++
		q += "$" + strconv.Itoa(n) + ","
		param = append(param, curId)
	}
	q = q[:len(q)-1]
	sqlStr := "UPDATE exam_option SET states=2, upd_time=EXTRACT(epoch FROM NOW()) WHERE qst_id IN (" + q + ")"
	db.CudData(sqlStr, param...)
	<-ch
}

// One 获取详情
func (s *quest) One(qstId string) *utils.ResJson {
	sqlStr := "SELECT a.qst_id, a.kind, a.qst_no, a.title, a.answer, a.keywords, a.file_names, a.file_urls, a.remarks, a.states, a.add_time, a.upd_time FROM exam_base a WHERE a.qst_id=$1"
	return db.GetOne(sqlStr, qstId)
}

// List 获取选项列表
func (s *quest) List(qstId string) *utils.ResJson {
	sqlStr := "SELECT a.opt_id, a.qst_id, a.opt_no, a.opt_name, a.img_names, a.img_urls, a.iz_right, a.answer, a.keywords, a.remarks, a.states, a.add_time, a.upd_time " +
		"FROM exam_option a WHERE a.states=1 AND a.qst_id=$1 ORDER BY a.opt_no"
	return db.GetAll(sqlStr, qstId)
}

// Count 获取数量
func (s *quest) Count(req *exam_mod.QstPageReq) *utils.ResJson {
	sqlStr := "SELECT COUNT(1) AS nums FROM exam_base WHERE states=1"
	param := make([]any, 0)
	var n = 0
	if req.Keywords != "" {
		sqlStr += " AND ("
		nameArr := strings.Split(req.Keywords, " ")
		for _, name := range nameArr {
			sqlStr += "title LIKE '%'||$" + strconv.Itoa(n+1) + "||'%' OR " +
				"qst_no LIKE '%'||$" + strconv.Itoa(n+2) + "||'%' OR " +
				"answer LIKE '%'||$" + strconv.Itoa(n+3) + "||'%' OR " +
				"keywords LIKE '%'||$" + strconv.Itoa(n+4) + "||'%' OR "
			param = append(param, name)
			param = append(param, name)
			param = append(param, name)
			param = append(param, name)
			n += 4
		}
		sqlStr = sqlStr[:len(sqlStr)-4]
		sqlStr += ")"
	}
	if req.Kind != 0 {
		sqlStr += " AND kind=$" + strconv.Itoa(n+1)
		param = append(param, req.Kind)
		n++
	}
	if res := db.GetOne(sqlStr, param...); res.Code == utils.Succeed.Code && res.Data.(map[string]any)["nums"].(int64) > 0 {
		return res
	}
	return utils.NoData
}

// Page 获取分页列表
func (s *quest) Page(req *exam_mod.QstPageReq) *utils.ResJson {
	sqlStr := "SELECT a.qst_id, a.kind, a.qst_no, a.title, a.answer, a.keywords, a.states, a.add_time " +
		"FROM exam_base a " +
		"WHERE a.states=1"
	param := make([]any, 0)
	var n = 0
	if req.Keywords != "" {
		sqlStr += " AND ("
		nameArr := strings.Split(req.Keywords, " ")
		for _, name := range nameArr {
			sqlStr += "a.title LIKE '%'||$" + strconv.Itoa(n+1) + "||'%' OR " +
				"a.qst_no LIKE '%'||$" + strconv.Itoa(n+2) + "||'%' OR " +
				"a.answer LIKE '%'||$" + strconv.Itoa(n+3) + "||'%' OR " +
				"a.keywords LIKE '%'||$" + strconv.Itoa(n+4) + "||'%' OR "
			param = append(param, name)
			param = append(param, name)
			param = append(param, name)
			param = append(param, name)
			n += 4
		}
		sqlStr = sqlStr[:len(sqlStr)-4]
		sqlStr += ")"
	}
	if req.Kind != 0 {
		sqlStr += " AND kind=$" + strconv.Itoa(n+1)
		param = append(param, req.Kind)
		n++
	}
	sqlStr += " ORDER BY a.kind, a.qst_no LIMIT $" + strconv.Itoa(n+1) + " OFFSET $" + strconv.Itoa(n+2)
	param = append(param, req.Limit)
	param = append(param, req.Offset)
	return db.GetAll(sqlStr, param...)
}

// Sort 排序
func (s *quest) Sort(kind uint8) *utils.ResJson {
	sqlStr := "SELECT COUNT(1)+1 AS nums FROM exam_base WHERE states=1 AND kind=$1"
	res := db.GetOne(sqlStr, kind)
	return &utils.ResJson{Code: utils.Succeed.Code, Msg: utils.Succeed.Msg, Data: res.Data.(map[string]any)["nums"].(int64)}
}

// AddQsts 批量插入题
func (s *quest) AddQsts(list []*exam_mod.QstSaveReq) {
	var (
		param []any
		n     = 0
	)
	sqlStr := "INSERT INTO exam_base(qst_id, kind, qst_no, title, answer, keywords, file_names, file_urls, remarks, states, add_time, upd_time) VALUES "
	for _, req := range list {
		sqlStr += "($" + strconv.Itoa(n+1) + ", $" + strconv.Itoa(n+2) + ", $" + strconv.Itoa(n+3) + ", $" + strconv.Itoa(n+4) + ", $" + strconv.Itoa(n+5) + ", $" + strconv.Itoa(n+6) + ", $" + strconv.Itoa(n+7) + ", $" + strconv.Itoa(n+8) + ", $" + strconv.Itoa(n+9) + ", 1, EXTRACT(epoch FROM NOW()), EXTRACT(epoch FROM NOW())),"
		param = append(param, req.QstId)
		param = append(param, req.Kind)
		param = append(param, req.QstNo)
		param = append(param, req.Title)
		param = append(param, req.Answer)
		param = append(param, req.Keywords)
		param = append(param, req.FileNames)
		param = append(param, req.FileUrls)
		param = append(param, req.Remarks)
		n += 9
	}
	sqlStr = sqlStr[:len(sqlStr)-1]
	db.CudData(sqlStr, param...)
}
